﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Data;

namespace Music_Organizer
{
    class Music
    {
        private ProgressBarWindow pbWindow = null;

        public struct MusicTagList //Stores information about a song
        {
            public TagLib.File tagFile;
            public string originalPath;
            public string destinationPath;
        }

        public Music()
        {

        }

        public void ImportFolder(string importFolder) //This is the method I entend to be called if the user wants to import a music folder.
        {
            pbWindow = new ProgressBarWindow();  //Creates progress window that will show the progress of the import
            pbWindow.Show();

            Thread wImportFolder = new Thread(WorkerImportFolder); //Kicks off a worker to search the folders and move the files.  This activity can take a few min.
            wImportFolder.IsBackground = true;
            wImportFolder.Start(importFolder);
        }
        private void WorkerImportFolder(object oWorkerRoot) //Worker for the import folder task.
        {
            /*
            string workerRoot = (string)oWorkerRoot; //Root folder that the worker is importing from.
            bool workerCancel = false; //Turns to true if the worker should quit.

            if (pbWindow.clo) //If the progress bar closes the worker should quit, otherwise update the progress bar.
                pbWindow.Invoke(new PerformWorkerUpdateCallback(this.PerformWorkerUpdate), new object[] { "Scanning Folder", 0, true });
            else
                workerCancel = true;
            
            //This is old code, should be replaced with a better way to handle the data
            MusicTagEditor userTagEditor = new MusicTagEditor(MusicReadTags(workerRoot, true)); //Read the tags and search subfolders and then let the user see what's being imported
            userTagEditor.ShowDialog();
                            
            MusicTagList[] importList = userTagEditor.TagList;  
            
              
            for (int i = 0; i < importList.Length; i++) //Start the moving of files.
            {
                //Invalid chars must be removed.
                string invalid = new string(System.IO.Path.GetInvalidFileNameChars()) + new string(System.IO.Path.GetInvalidPathChars()); //List of all invalid chars

                string artist = importList[i].tagFile.Tag.Performers[0];
                string album = importList[i].tagFile.Tag.Album;
                string title = importList[i].tagFile.Tag.Title;
                string format = System.IO.Path.GetExtension(importList[i].originalPath);

                if (!pbWindow.Closed) //Update the progress bar if it is still open
                {
                    try
                    {
                        pbWindow.Invoke(new PerformWorkerUpdateCallback(this.PerformWorkerUpdate), new object[] { "Coping: " + artist, (int)((double)i / (double)(importList.Length - 1) * 100.00), true });
                    }
                    catch
                    {
                    }
                }
                else
                {
                    workerCancel = true; //If the progress bar was closed then end the import.
                }

                //Replace invalid chars
                foreach (char c in invalid)
                    artist = artist.Replace(c.ToString(), "");
                foreach (char c in invalid)
                    album = album.Replace(c.ToString(), "");
                foreach (char c in invalid)
                    title = title.Replace(c.ToString(), "");
                foreach (char c in invalid)
                    format = format.Replace(c.ToString(), "");

                //Standard folder names and file names
                string subfolder = artist + @"\" + album;
                string fileName = importList[i].tagFile.Tag.Track + " - " + title + format;

                //Update the destination path
                importList[i].destinationPath = musicRoot + @"\" + subfolder + @"\" + fileName;

                //Create the folder to move the files to
                CreateFolder(musicRoot, subfolder);

                //Copy the file to the new location
                CopyFile(importList[i]);

                //Cancel the worker if requested
                if (workerCancel)
                    break;
            }

            //Update the pbWindow if the job is done.
            if (!pbWindow.Closed)
                pbWindow.Invoke(new PerformWorkerUpdateCallback(this.PerformWorkerUpdate), new object[] { "Complete", 100, false });
        
             */
        }

        /// <summary>
        /// Scans a folder for music files and returns the data in a datatable.
        /// </summary>
        /// <param name="searchFolder">Folder that the method will search.</param>
        public DataTable SearchFolder(string searchFolder)
        {
            DataTable rDataTable = new DataTable();

            MusicTagList[] tags = MusicReadTags(searchFolder, true);
            tags = CleanTags(tags);

            rDataTable.Columns.Add("Title");
            rDataTable.Columns.Add("Artist");
            rDataTable.Columns.Add("Album");
            rDataTable.Columns.Add("Genre");
            rDataTable.Columns.Add("Path");
            rDataTable.Columns.Add("Year");
            rDataTable.Columns.Add("Track");
            rDataTable.Columns.Add("Extention");

            for (int i = 0; i < tags.Length; i++)
            {
                object[] row = new object[rDataTable.Columns.Count];
                row[0] = tags[i].tagFile.Tag.Title;
                row[1] = tags[i].tagFile.Tag.Performers[0];
                row[2] = tags[i].tagFile.Tag.Album;
                row[3] = tags[i].tagFile.Tag.Genres[0];
                row[4] = tags[i].destinationPath;
                row[5] = tags[i].tagFile.Tag.Year;
                row[6] = tags[i].tagFile.Tag.Track;
                row[7] = System.IO.Path.GetExtension(tags[i].originalPath);

                rDataTable.Rows.Add(row);
            }

            return rDataTable;
        }

        private MusicTagList[] MusicReadTags(string searchFolder, bool searchSubfolders)  //Method to scan for music files.  Right now it only searches for .mp3 and .flac
        {
            MusicTagList[] tagList = new MusicTagList[0]; //Variable to be returned at the end

            if (System.IO.Directory.Exists(searchFolder))//Confirm the folder exsists
            {

                //Start by searching this folder
                string[] allFiles = System.IO.Directory.GetFiles(searchFolder); //All files in root folder

                //Decide which files are supported and keep track of it.  This is used to decide how big the array of tags needs to be.
                int supportedFiles = 0;
                for (int i = 0; i < allFiles.Length; i++) //Create tagList for root
                {
                    if (allFiles[i].Contains(".mp3") || allFiles[i].Contains(".flac"))
                    {
                        try
                        {
                            TagLib.File.Create(allFiles[i]);
                            supportedFiles++;
                        }
                        catch
                        {

                        }
                    }
                }

                tagList = new MusicTagList[supportedFiles]; //Set taglist to the number of files in root that are supported

                int supportedFile = 0;
                for (int i = 0; i < allFiles.Length; i++) //Create tagList for root
                {
                    if (supportedFiles > supportedFile)
                    {
                        if (allFiles[i].Contains(".mp3") || allFiles[i].Contains(".flac"))
                        {
                            try
                            {
                                tagList[supportedFile].tagFile = TagLib.File.Create(allFiles[i]);
                                tagList[supportedFile].originalPath = allFiles[i];
                                tagList[supportedFile].destinationPath = allFiles[i];
                                supportedFile++;
                            }
                            catch
                            {
                                System.Windows.Forms.MessageBox.Show("Error with... " + allFiles[i] + " so the file is being deleted");
                                System.IO.File.Delete(allFiles[i]);
                                return MusicReadTags(searchFolder, searchSubfolders); //Call this again and return the result.  This will recreate all the correctly sized arrays.
                            }

                        }
                    }
                }

                if (searchSubfolders && System.IO.Directory.GetDirectories(searchFolder).Length > 0) //Do we need to search subfolders?
                {
                    string[] subFolders = System.IO.Directory.GetDirectories(searchFolder); //Get list of subfolders

                    for (int i = 0; i < subFolders.Length; i++) //Begin searching the subfolders
                    {
                        MusicTagList[] subfolderTagList = MusicReadTags(subFolders[i], true); //Search subfolder for tags.  Method calls itself to search subfolders.  To the new method the subfolder looks like a root folder.

                        //Add new tags to the complete subfolder list
                        MusicTagList[] tmpTagList = tagList; //Create tmp tag list
                        tagList = new MusicTagList[subfolderTagList.Length + tmpTagList.Length]; //Reinit the tag list making it bigger
                        for (int j = 0; j < tmpTagList.Length; j++)
                        {
                            tagList[j] = tmpTagList[j];
                        }
                        for (int j = 0; j < subfolderTagList.Length; j++)
                        {
                            tagList[tmpTagList.Length + j] = subfolderTagList[j];
                        }
                    }
                }
            }
            return tagList;
        }
        private MusicTagList[] CleanTags(MusicTagList[] tags)
        {
            for (int i = 0; i < tags.Length; i++)
            {
                bool saveRequired = false;
                if (tags[i].tagFile.Tag.Performers[0] == null || tags[i].tagFile.Tag.Performers[0] == "")
                {
                    tags[i].tagFile.Tag.Performers[0] = "Unknown Artist";// tags[i].tagFile.Tag.Artists[0];
                    saveRequired = true;
                }

                if (saveRequired)
                {
                    tags[i].tagFile.Save();
                }
            }

            return tags;
        }

        /// <summary>
        /// Generates a path for a music file.  Uses the title, artist, album, and file extention.
        /// </summary>
        /// <param name="DT">Datatable containing information about the file being moved.  Requires title, artist, album, and file extention.</param>
        /// <param name="rootPath">Root path or directory where the file will be stored.</param>
        public string GeneratePath(DataRow DR, string rootPath)
        {
            if (!DR.Table.Columns.Contains("Title") || !DR.Table.Columns.Contains("Album") || !DR.Table.Columns.Contains("Artist") || !DR.Table.Columns.Contains("Extention"))
                throw new Exception("Missing either title, album, or artist in datatable for GeneratePath");

            return rootPath + @"\" + DR["Artist"] + @"\" + DR["Album"] + @"\" + DR["Title"] + DR["Extention"];
        }
    }
}
